#pragma once

#include <vector>

#include "detail.hpp"
#include "fields.hpp"
#include "abstract.hpp"

namespace JsonRpc
{
    using Address = std::pair<std::string, uint16_t>;

    class JsonMessage : public BaseMessage
    {
    public:
        using ptr = std::shared_ptr<JsonMessage>;
        
        virtual ~JsonMessage() {}
        virtual bool check() = 0;

        virtual std::string serialize() override
        {
            std::string body;
            bool ret = JSON::Serialize(_body, body);
            if (ret == false)
            {
                return std::string();
            }

            return body;
        }
        virtual bool deserialize(const std::string &msg) override
        {
            return JSON::Deserialize(msg, _body);
        }

    protected:
        Json::Value _body;
    };

    class JsonRequest : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonRequest>;
        
        virtual ~JsonRequest() {};
        virtual bool check() = 0;

    };

    class JsonResponse : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonResponse>;

        virtual ~JsonResponse() {}
        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() == true)
            {
                LOG(ERROR, "响应中没有响应状态码！\n");
                return false;
            }
            if (_body[KEY_RCODE].isIntegral() == false)
            {
                LOG(ERROR, "响应状态码类型错误！\n");
                return false;
            }
            return true;
        }
        virtual RCode rcode() { return static_cast<RCode>(_body[KEY_RCODE].asInt()); }
        virtual void setRCode(RCode rcode) { _body[KEY_RCODE] = static_cast<int>(rcode); }
    };

    class RpcRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<RpcRequest>;

        virtual ~RpcRequest() {}
        virtual bool check() override
        {
            if (_body[KEY_METHOD].isNull() == true ||
                _body[KEY_METHOD].isString() == false)
            {
                LOG(ERROR, "RPC请求中没有方法名称或方法名称类型错误！\n");
                return false;
            }
            if (_body[KEY_PARAMS].isNull() == true ||
            _body[KEY_PARAMS].isObject() == false)
            {
                LOG(ERROR, "RPC请求中没有参数名称或参数名称类型错误！\n");
                return false;
            }
            return true;
        }
        virtual std::string method() { return _body[KEY_METHOD].asString(); }
        virtual void setMethod(const std::string &method_name) { _body[KEY_METHOD] = method_name; }

        virtual Json::Value params() { return _body[KEY_PARAMS]; }
        virtual void setParams(const Json::Value &params) { _body[KEY_PARAMS] = params; }
    };

    class TopicRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<TopicRequest>;

        virtual ~TopicRequest() {}
        virtual bool check() override
        {
            if (_body[KEY_TOPIC_KEY].isNull() == true ||
                _body[KEY_TOPIC_KEY].isString() == false)
            {
                LOG(ERROR, "主题请求中没有主题名称或主题名称类型错误！\n");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true ||
            _body[KEY_OPTYPE].isIntegral() == false)
            {
                LOG(ERROR, "主题请求中没有操作类型或操作类型的类型错误！\n");
                return false;
            }
            if (TopicOptype::TOPIC_PUBLISH == static_cast<TopicOptype>(_body[KEY_OPTYPE].asInt()) &&
                _body[KEY_TOPIC_MSG].isNull() == true ||
                _body[KEY_TOPIC_MSG].isString() == false)
            {
                LOG(ERROR, "主题消息发布请求中没有消息内容字段或消息内容类型错误！\n");
                return false;
            }
            return true;
        }
        virtual std::string topicKey() { return _body[KEY_METHOD].asString(); }
        virtual void setTopicKey(const std::string &topicKey) { _body[KEY_METHOD] = topicKey; }

        virtual TopicOptype optype() { return static_cast<TopicOptype>(_body[KEY_OPTYPE].asInt()); }
        virtual void setOptype(TopicOptype optype) { _body[KEY_PARAMS] = static_cast<int>(optype); }

        virtual std::string topicMsg() { return _body[KEY_METHOD].asString(); }
        virtual void setTopicMsg(const std::string &msg) { _body[KEY_METHOD] = msg; }
    };

    class ServiceRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<ServiceRequest>;

        virtual ~ServiceRequest() {}
        virtual bool check() override
        {
            //rpc请求中，包含请求方法名称-字符串，参数字段-对象
            if (_body[KEY_METHOD].isNull() == true ||
                _body[KEY_METHOD].isString() == false) 
            {
                LOG(ERROR, "服务请求中没有方法名称或方法名称类型错误！\n");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true ||
                _body[KEY_OPTYPE].isIntegral() == false) 
            {
                LOG(ERROR, "服务请求中没有操作类型或操作类型的类型错误！\n");
                return false;
            }
            if (ServiceOptype::SERVICE_DISCOVERY != static_cast<ServiceOptype>(_body[KEY_OPTYPE].asInt()) ||
                _body[KEY_HOST].isNull() == true ||
                _body[KEY_HOST].isObject() == false ||
                _body[KEY_HOST][KEY_HOST_IP].isNull() == true ||
                _body[KEY_HOST][KEY_HOST_IP].isString() == false ||
                _body[KEY_HOST][KEY_HOST_PORT].isNull() == true ||
                _body[KEY_HOST][KEY_HOST_PORT].isIntegral() == false)
            {
                LOG(ERROR, "服务请求中主机地址信息错误！\n");
                return false;
            }

            return true;
        }
        virtual std::string method() { return _body[KEY_METHOD].asString(); }
        virtual void setMethod(const std::string &method_name) { _body[KEY_METHOD] = method_name; }

        virtual ServiceOptype optype() { return static_cast<ServiceOptype>(_body[KEY_OPTYPE].asInt()); }
        virtual void setOptype(ServiceOptype optype) { _body[KEY_PARAMS] = static_cast<int>(optype); }

        virtual Address host()
        {
            Address addr;
            addr.first = _body[KEY_HOST][KEY_HOST_IP].asString();
            addr.second = _body[KEY_HOST][KEY_HOST_PORT].asInt();
            return addr;
        }
        virtual void setHost(const Address &host)
        {
            Json::Value val;
            val[KEY_HOST_IP] = host.first;
            val[KEY_HOST_PORT] = host.second;
            _body[KEY_HOST] = val;
        }
    };

    class RpcResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<RpcResponse>;

        virtual ~RpcResponse() {}
        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() == true ||
                _body[KEY_RCODE].isIntegral() == false)
            {
                LOG(ERROR, "响应状态码错误！\n");
                return false;
            }
            if (_body[KEY_RESULT].isNull() == true)
            {
                LOG(ERROR, "响应Rpc结果错误！\n");
                return false;
            }
            return true;
        }
        virtual Json::Value result() { return _body[KEY_RESULT]; }
        virtual void setResult(const Json::Value& result) { _body[KEY_RESULT] = result; }
        
    };

    class TopicResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<TopicResponse>;

        virtual ~TopicResponse() {}
    };

    class ServiceResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<ServiceResponse>;

        virtual ~ServiceResponse() {}

        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() == true ||
                _body[KEY_RCODE].isIntegral() == false)
            {
                LOG(ERROR, "响应状态码错误！\n");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true ||
                _body[KEY_OPTYPE].isIntegral() == false) 
            {
                LOG(ERROR, "响应操作类型错误\n");
                return false;
            }
            if (ServiceOptype::SERVICE_DISCOVERY == static_cast<ServiceOptype>(_body[KEY_OPTYPE].asInt()) &&
                _body[KEY_METHOD].isNull() == true ||
                _body[KEY_METHOD].isString() == false ||
                _body[KEY_HOST].isNull() == true ||
                _body[KEY_HOST].isObject() == false)
            {
                LOG(ERROR, "服务发现响应中响应信息字段错误！\n");
                return false;
            }
            return true;
        }
        virtual ServiceOptype optype() { return static_cast<ServiceOptype>(_body[KEY_OPTYPE].asInt()); }
        virtual void setOptype(ServiceOptype optype) { _body[KEY_PARAMS] = static_cast<int>(optype); }

        virtual std::string method() { return _body[KEY_METHOD].asString(); }
        virtual void setMethod(const std::string &method_name) { _body[KEY_METHOD] = method_name; }

        void setHosts(std::vector<Address> &addrs)
        {
            for (auto &addr : addrs) 
            {
                Json::Value val;
                val[KEY_HOST_IP] = addr.first;
                val[KEY_HOST_PORT] = addr.second;
                _body[KEY_HOST].append(val);
            }
        }
        virtual std::vector<Address> hosts()
        {
            std::vector<Address> addrs;
            int sz = _body[KEY_HOST].size();
            for (int i = 0; i < sz; ++i)
            {
                Address addr;
                addr.first = _body[KEY_HOST][i][KEY_HOST_IP].asString();
                addr.second = _body[KEY_HOST][i][KEY_HOST_PORT].asInt();
                addrs.push_back(addr);
            }
            return addrs;
        }
    };

    class MessageFactory
    {
    public:
        static BaseMessage::ptr create(MType mtype)
        {
            switch(mtype)
            {
                case MType::REQ_RPC : return std::make_shared<RpcRequest>();
                case MType::RSP_RPC : return std::make_shared<RpcResponse>();
                case MType::REQ_TOPIC : return std::make_shared<TopicRequest>();
                case MType::RSP_TOPIC : return std::make_shared<TopicResponse>();
                case MType::REQ_SERVICE : return std::make_shared<ServiceRequest>();
                case MType::RSP_SERVICE : return std::make_shared<ServiceResponse>();
            }
        }

        template<typename T, typename ...Args>
        static std::shared_ptr<T> create(Args&& ...args)
        {
            return std::make_shared<T>(std::forward<Args>(args)...);
        }
    };
}